mod common_model;
pub mod model;

use crate::common_model::{ApiResponse, AppConfig, ServiceError};
use crate::model::dto::TaskDTO;
use crate::model::{Book, SiteInfo};
use anyhow::Result;
use config::{Config, Environment, File};
use log::info;
use reqwest::{Client, Response};
use serde::Deserialize;
use std::{collections::HashMap, env};
use url::Url;

fn get_config_path(filename: &str) -> String {
    // 获取当前可执行文件的路径
    let mut path = env::current_exe().unwrap();
    path.pop(); // 跳到可执行文件所在目录
    path.push(filename);
    path.to_string_lossy().to_string()
}
// 服务主体
pub struct GWebRemoteService {
    pub config: AppConfig, // 应用程序配置，包含所有从配置文件读取的设置
    client: Client,        // HTTP 客户端，用于发送网络请求
}

impl GWebRemoteService {
    /// 创建新的 GWebRemoteService 实例
    ///
    /// # 返回值
    /// - `Ok(Self)`: 成功创建服务实例
    /// - `Err(ServiceError)`: 配置加载失败或解析错误
    ///
    /// # 配置加载规则
    /// 配置按以下顺序加载（后面的配置会覆盖前面的）：
    /// 1. `application-remote.json` - 基础配置（必须存在）
    /// 2. `application-remote-{env}.json` - 环境特定配置（可选）
    /// 3. 环境变量 - 最高优先级（使用 APP__ 前缀）
    ///
    /// # 环境变量
    /// - `APP_ENV`: 指定运行环境，默认为 "dev"
    /// - `APP__*`: 用于覆盖配置项，如 `APP__DATABASE__HOST=localhost`
    pub fn new() -> Result<Self, ServiceError> {
        // 获取环境变量，如果没有设置则默认为 "dev"
        // 例如：设置 APP_ENV=prod 使用生产环境配置
        let env = env::var("APP_ENV").unwrap_or_else(|_| "dev".to_string());

        info!("运行在{}！！！环境", env);

        // 读取基础配置和环境特定配置
        let config = Config::builder()
            // 第一层：基础配置（必须存在）
            // 加载 application-remote.json 文件，包含所有环境的共享配置
            .add_source(File::with_name(&get_config_path("application-remote.json")).required(true))
            // 第二层：环境特定配置（可选）
            // 根据环境变量加载对应的配置文件，如：
            // - dev 环境: application-remote-dev.json
            // - prod 环境: application-remote-prod.json
            // - test 环境: application-remote-test.json
            // required(false) 表示文件可以不存在，不会报错
            .add_source(
                File::with_name(&get_config_path(&format!(
                    "application-remote-{}.json",
                    env
                )))
                .required(false),
            )
            // 第三层：环境变量覆盖（可选），最高优先级
            // 使用 APP__ 前缀的环境变量可以覆盖文件中的配置
            // separator("__") 表示使用双下划线作为嵌套分隔符
            // 例如：APP__DATABASE__HOST=localhost 会覆盖配置文件中的 database.host
            .add_source(Environment::with_prefix("APP").separator("__"))
            // 构建配置对象
            .build()?
            // 将配置反序列化为 AppConfig 结构体
            .try_deserialize::<AppConfig>()?;

        Ok(Self {
            config,                // 解析后的配置对象
            client: Client::new(), // 创建新的 HTTP 客户端
        })
    }

    pub async fn list_sites(&self) -> Result<Option<Vec<SiteInfo>>, ServiceError> {
        let url = &self.config.url.source_sites;
        info!("！！！！发送查询站点请求，url={}", url);
        let response = self.client.post(url).send().await?;
        let api_resp = self.handle_response::<Vec<SiteInfo>>(response).await?;
        //因为v.data的结果也是Option，使用and_then保留一层，如果使用map的话会有两层Option
        Ok(api_resp.data)
    }

    pub async fn get_task(&self, site_id: i32) -> Result<Option<TaskDTO>, ServiceError> {
        let url = &self.config.url.get_task;
        info!("！！！！发送获取任务请求,url={}", url);
        let mut params = HashMap::new();
        params.insert("ssid", site_id.to_string());

        let response = self.client.post(url).form(&params).send().await?;
        let api_resp = self.handle_response::<TaskDTO>(response).await?;
        Ok(api_resp.data)
    }

    pub async fn modify_site_last_check_date_by_site_id(
        &self,
        site_id: i32,
        time: chrono::DateTime<chrono::Utc>,
    ) -> Result<(), ServiceError> {
        let url = &self.config.url.update_site_last_check_date;

        let mut params = HashMap::new();
        params.insert("ssid", site_id.to_string());
        params.insert("time", time.format("%Y-%m-%d %H:%M:%S").to_string());

        let response = self.client.post(url).form(&params).send().await?;
        response.error_for_status()?;

        Ok(())
    }

    pub async fn insert_book(&self, book: &Book) -> Result<(), ServiceError> {
        let url = &self.config.url.upload_book_and_chapters;

        let params = self.book_to_params(book);
        let response = self.client.post(url).form(&params).send().await?;
        response.error_for_status()?;

        Ok(())
    }

    pub async fn check_book_if_exist(&self, site_id: i32, uk: &str) -> Result<bool, ServiceError> {
        let base_url = &self.config.url.get_book;
        let mut url = Url::parse(base_url)?;

        url.query_pairs_mut()
            .append_pair("ssid", &site_id.to_string())
            .append_pair("uk", uk);

        let response = self.client.post(url).send().await?;
        let api_response: ApiResponse<Book> = response.json().await?;

        match api_response.code {
            200 => Ok(true),
            201 => Ok(false),
            _ => Err(ServiceError::Api {
                code: api_response.code,
                message: api_response.msg,
            }),
        }
    }

    pub async fn upload_video_slice_result(
        &self,
        site_id: i32,
        chapter_id: i32,
        path: &str,
        state: i32,
        err: Option<&str>,
    ) -> Result<(), ServiceError> {
        let url = &self.config.url.upload_video_slice_result;
        info!("！！！！上报任务结果请求,url={}", url);
        let mut params = HashMap::new();
        params.insert("ssid", site_id.to_string());
        params.insert("chapterid", chapter_id.to_string());
        params.insert("path", path.to_string());
        params.insert("state", state.to_string());
        if let Some(err) = err {
            params.insert("err", err.to_string());
        }

        let response = self.client.post(url).form(&params).send().await?;
        response.error_for_status()?;
        Ok(())
    }

    // 辅助方法：处理 API 响应
    async fn handle_response<T: for<'de> Deserialize<'de>>(
        &self,
        response: Response,
    ) -> Result<ApiResponse<T>, ServiceError> {
        let text = response.text().await?;
        let parsed: ApiResponse<T> = serde_json::from_str(&text)?;
        Ok(parsed)
    }

    // 辅助方法：将 Book 转换为表单参数
    fn book_to_params(&self, book: &Book) -> HashMap<&str, String> {
        let mut params = HashMap::new();

        // 根据实际的 Book 结构体字段进行映射
        params.insert("ssid", book.site_id.to_string());

        if let Some(ref url) = book.url {
            params.insert("url", url.clone());
        }

        if let Some(ref uk) = book.uk {
            params.insert("uk", uk.clone());
        }

        if let Some(ref name) = book.name {
            params.insert("name", name.clone());
        }

        params.insert("finish", book.finish.to_string());

        if let Some(ref chapters) = book.chapters {
            params.insert("chapters", chapters.clone());
        }

        if let Some(ref cover) = book.cover {
            params.insert("cover", cover.clone());
        }

        params
    }
}
